/**
 * 
 */
package t4j.concurrency;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
//膳食
class Meal{
	private final int orderNum;
	
	public Meal(int orderNum){ this.orderNum = orderNum; }

	public String toString(){ 
		return "Meal " + orderNum;
	}
}
//服务员
class WaitPerson implements Runnable{
	private Restaurant restaurant;

	public WaitPerson(Restaurant r){
		restaurant = r;
	}

	@Override
	public void run() {
		try{
			while(!Thread.interrupted()){
				
				synchronized(this){
					while(restaurant.meal == null)
						wait();
				}
			
				System.out.println("Waitperson got " + restaurant.meal);
				
				synchronized (restaurant.chef) {
					restaurant.meal = null;//清空晚餐
					restaurant.chef.notifyAll();//ready for another，唤醒厨师
				}
			}
		}catch(InterruptedException e){
			System.out.println("WaitPerson interrupted");
		}
	}
}

class Chef implements Runnable{

	private Restaurant restaurant;
	private int count = 0 ;
	
	public Chef(Restaurant r) {
		restaurant = r;
	}
	
	@Override
	public void run() {
		
		try{
			while(!Thread.interrupted()){
				
				synchronized (this) {
					while(restaurant.meal != null)
						wait();
				}
				
				if(++count == 10){
					System.out.println("Out of food, closing");
					restaurant.exec.shutdownNow();
					
				}
				
				System.out.print("Order up! ");
				
				synchronized (restaurant.waitPerson) {
					restaurant.meal = new Meal(count);//新建一个晚餐
					restaurant.waitPerson.notifyAll();//等待的人任务被唤醒
				}
				
				//因为当任务试图进入一个（可中断）的阻塞操作时，这个中断才能抛错
				TimeUnit.MILLISECONDS.sleep(100);//试图调用sleep()时，中断才抛错，否则删除这句的话，中断不会抛错，并回到run循环的顶部
			}
		}catch(InterruptedException e){
			System.out.println("Chef interrupted");
		}
		
	}
	
}

//餐馆
public class Restaurant {
	ExecutorService exec = Executors.newCachedThreadPool();
	Meal meal;
	Chef chef = new Chef(this);
	WaitPerson waitPerson = new WaitPerson(this);
	
	public Restaurant() {
		
		exec.execute(chef);
		exec.execute(waitPerson);
	}
	
	public static void main(String[] args) {
		new Restaurant();
	}
}
